﻿using System.Diagnostics;

namespace DimensionsHelper.LanguageService.Syntax;

/// <summary>
///     二元表达式
/// </summary>
public class BinaryExpression : Expression
{
    private Expression _leftOperand;

    private SyntaxToken _operatorToken;
    private Expression _rightOperand;

    internal BinaryExpression(Expression left, SyntaxToken oper, SyntaxNode? parent) :
        base(SyntaxKinds.BinaryExpression, parent)
    {
        _leftOperand = EmptyExpression.Default;
        _rightOperand = EmptyExpression.Default;
        _operatorToken = oper;

        if (!left.IsEmpty)
        {
            SetChildField(ref _leftOperand, IsEmptyExpression, left);
        }
    }


    protected BinaryExpression(SyntaxKinds kind, Expression leftOperand, SyntaxToken oper, SyntaxNode? parent) :
        base(kind, parent)
    {
        _leftOperand = leftOperand;
        _rightOperand = EmptyExpression.Default;
        _operatorToken = oper;
    }


    /// <summary>
    ///     二元操作符
    /// </summary>
    public SyntaxToken OperatorToken => _operatorToken;

    /// <summary>
    ///     左值表达式
    /// </summary>
    public Expression LeftOperand => _leftOperand;

    /// <summary>
    ///     右值表达式
    /// </summary>
    public Expression RightOperand => _rightOperand;


    public override void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor)
    {
        Accept(visitor, LeftOperand, OperatorToken, RightOperand);
        base.AcceptVisitor(visitor);
    }


    public BinaryExpression Update(SyntaxToken operatorToken)
    {
        Debug.Assert(SyntaxFacts.IsBinaryOperatorUnchecked(operatorToken.Kind));
        SetChildField(ref _operatorToken, SyntaxToken.IsNullOrEmpty, operatorToken);
        return this;
    }


    public BinaryExpression Update(Expression rightOperand)
    {
        SetChildField(ref _rightOperand, IsEmptyExpression, rightOperand);
        return this;
    }


    public BinaryExpression Update(Expression leftOperand, Expression rightOperand)
    {
        SetChildField(ref _leftOperand, IsEmptyExpression, leftOperand);
        SetChildField(ref _rightOperand, IsEmptyExpression, rightOperand);
        return this;
    }
}


public static partial class NodeFactory
{
    public static BinaryExpression CreateBinaryExpression(SyntaxNode? parent, SyntaxToken operatorToken,
        Expression leftOperand, Expression rightOperand)
    {
        Debug.Assert(SyntaxFacts.IsBinaryOperatorUnchecked(operatorToken.Kind));
        BinaryExpression binaryExpression = new(leftOperand, operatorToken, parent);
        return binaryExpression.Update(rightOperand);
    }


    public static BinaryExpression CreateBinaryExpression(SyntaxToken operatorToken, Expression leftOperand,
        Expression rightOperand)
    {
        return CreateBinaryExpression(null, operatorToken, leftOperand, rightOperand);
    }
}